#!/usr/bin/env python
# $Id: servcontract.py df54dec975f4 2012/09/09 20:22:40 pgurumur $
# Copyright (c) 2012 Prabhu Gurumurthy <pgurumur@gmail.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

__version__  = "$Revision: df54dec975f4 $"
__author__   = "$Author: pgurumur $"
__modified__ = "$Date: 2012-09-09 20:22:40Z $"

import optparse
import os
import sys
import time

from venya.lib import exception
from venya.lib import cmdparser
from venya.lib import config
from venya.lib import sql
from venya.lib import stdlib
from venya.lib import ip


class servcontract(cmdparser.GetOpt):
   option_list = (
         optparse.make_option("-f", "--file", type = "str",
            help = "SMARTNet contract in text file format", dest = "filename"),
         optparse.make_option("-c", "--config", type = "str",
            help = "Configuration file for netdot crendentials",
            default  = "db.cfg", dest = "config"),
         optparse.make_option("-p", "--print", action = "store_true",
            help = "Print service contracts in CSV format", dest = "csvprint"),
         optparse.make_option("-C", "--contract", type = "str",
            help = "Contract number to use", dest = "contract"),
         optparse.make_option("-s", "--start", type = "str",
            help = "Start date to use, format '17-Nov-08'", dest = "start"),
         optparse.make_option("-e", "--end", type = "str",
            help = "End date to use, format: '17-Nov-08'", dest = "end"),
   ) + cmdparser.GetOpt.option_list

   def __init__(self, **Keywords):
      super(servcontract, self).__init__(**Keywords)
      self._fh = None
      self._cfg = None
      self._netdb = None
      self._device = None
      self._contract = None
      self._entity = None
      self._ipblock = None
      self._host = []

   def GetContract(self, Contract):
      retval = None
      ix = [ maintid[0] for maintid in self._contract.q.filter(
         self._contract.number == str(Contract)).values(self._contract.id)]
      if ix:
         retval = ix[0]

      return retval

   def warn(self, fmt, *args):
      """
      @brief wrapper for print function using format and arguments
      @param self 'this' pointer for the class
      @param fmt format string
      @param args arguments corresponding for format
      """
      print("%s: %s" %(str(self), stdlib.sprintf(fmt, *args)))

   def GetDevice(self, Serial = None):
      retval = None
      ix = [ devid[0] for devid in self._device.q.filter(
         self._device.serialnumber == str(Serial)).values(self._device.id)]
      if ix:
         retval = ix[0]

      return retval

   def GetDeviceIP(self, Id = 0):
      retval = None
      ix = [ addr[0] for addr in self._device.q.filter(
         self._device.id == int(Id)).values(self._device.snmp_target)]
      if ix:
         addr = self._ipblock.q.filter(self._ipblock.id == ix[0]).all()[0]
         address = None
         try:
            address = ip.ip(int(addr[0]), version = 4)
         except exception.IPError as err:
            self.warn(err)
         else:
            retval = address

      return retval

   def GetDeviceName(self, Id = 0):
      retval = None
      ix = [ name[0] for name in self._device.q.filter(
         self._device.id == int(Id)).values(self._device.name)]
      if ix:
         rr = self._netdb.rr
         zone = self._netdb.zone
         jy = [ (zid, name) for (zid, name) in rr.q.filter(
            rr.id == ix[0]).values(rr.zone, rr.name)]
         name = jy[0][1]
         jy = [ zoneName[0] for zoneName in zone.q.filter(
            zone.id == int(jy[0][0])).values(zone.name)]
         if name and jy:
            retval = "%s.%s" %(name, jy[0])

      return retval


   def GetTime(self, Time = None):
      return time.strftime("%Y-%m-%d", time.strptime(" ".join(Time.split("-")),
         "%d %b %y"))

   def GetSerial(self, HostIP = None):
      retval = None
      addr = int(HostIP)
      ix = [ addrid[0] for addrid in self._ipblock.q.filter(
         self._ipblock.address == addr).values(self._ipblock.id)]
      if ix:
         serial = [ serial[0] for serial in self._device.q.filter(
            self._device.snmp_target == int(ix[0])).values(
               self._device.serialnumber)]
         if serial:
            retval = serial[0]

      return retval

   def SetContract(self, Contract, Serial, Start, End):
      if Serial:
         maintid = self.GetContract(Contract)
         devid = self.GetDevice(Serial)
         if maintid and devid:
            deviceip = self.GetDeviceIP(devid)
            device = self.GetDeviceName(devid)
            updated = self._device.SQLUpdate("serialnumber", Serial,
                  maint_contract = maintid,
                  maint_from = self.GetTime(Start),
                  maint_until = self.GetTime(End))
            if updated:
               print("%s contract: %s, start: %s, end: %s" %(
                  device, Contract, self.GetTime(Start), self.GetTime(End)))

   def handle(self):
      (options, args) = self.parse()

      self._host = []
      try:
         self._host = args[1:]
      except IndexError as err:
         pass

      dbName = None
      device = None
      if options.config:
         try:
            self._cfg = config.Lexer(options.config)
         except exception.LexerError as err:
            self.error(err)
         else:
            dbName = self._cfg.Netdot

      try:
         if dbName:
            self._netdb = sql.mysql(dbName.dbname,
                  dbName.dbhost, dbName.dbuser, dbName.dbpass)
      except exception.SQLError as err:
         self.error(err)
      else:
         self._device = self._netdb.device
         self._contract = self._netdb.maintcontract
         self._entity = self._netdb.entity
         self._ipblock = self._netdb.ipblock

      """
      ['4181607', 'SNTP', '403712396', 'SILVER SPRING NETWORKS', '555 BROADWAY
      ST', 'REDWOOD CITY', 'CA', '94063', '1', 'CISCO2921/K9', 'FTX1428AH7B',
      '548482065', 'CHASSIS', 'Cisco 2921 w/3 GE 4 EHWIC 3 DSP 1 SM 256MB CF
      512MB DRAM IPB', '18-Aug-10', '17-Aug-13', '31-Oct-16']
      """
      if options.contract:
         if options.start and options.end:
            start = end = None
            try:
               start = self.GetTime(options.start)
               end = self.GetTime(options.end)
            except ValueError as err:
               self.error("start and/or end date must have '17-Nov-08' format")

            for host in self._host:
               serial = None
               try:
                  serial = self.GetSerial(ip.ip(str(host)))
               except exception.IPError as err:
                  print(err)
                  continue
               else:
                  self.SetContract(options.contract, serial, start, end)
         else:
            self.error("Cannot proceed without start and end dates")
      elif options.filename and os.path.exists(options.filename):
         try:
            self._fh = open(options.filename, "r")
         except IOError as err:
            self.error(err)
         else:
            for lines in self._fh.readlines():
               line = lines.strip().split("\t")
               if len(line) > 15:
                  self.SetContract(line[0], line[10], line[14], line[15])

            self._fh.close()
      elif options.csvprint:
         print("foo")
            

if __name__ == "__main__":
   contract = None
   try:
      contract = servcontract(version = 1.0, args = sys.argv,
            usage = "[ host ]")
      if len(contract) <= 1:
         contract.printhelp()
      else:
         contract.handle()
   except exception.GetOptError as err:
      print(err)
      sys.exit(1)
